package io.virtualapp.delegate.hook.plugin;

import android.app.Application;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import com.lody.virtual.client.VClient;
import com.lody.virtual.client.ipc.VLocationManager;
import com.lody.virtual.client.ipc.VirtualLocationManager;
import com.lody.virtual.os.VUserHandle;
import com.lody.virtual.remote.vloc.VLocation;
import com.scorpion.IHook.XC_MethodHook;
import com.scorpion.IHook.XposedBridge;
import com.scorpion.IHook.XposedHelpers;

import static com.scorpion.IHook.XposedHelpers.findClass;

/**
 * Created by su on 2018/3/15.
 * 定位 hook
 */

public class LocationHook {
    private final String TAG = "LocationHook";
    private ClassLoader mClassLoader;
    private double sLatitude;
    private double sLongitude;
    private boolean sHooking;

    private final List<String> LISTENER_CLASS = new ArrayList<>();
    private final List<String> LISTENER_PACKAGE = new ArrayList<>(
            Arrays.asList(
                    "com.alibaba.android.rimet",
                    "com.ss.android.lark"
            )
    );

    public void hook(String packageName, String processName, Application application) {
        if (!LISTENER_PACKAGE.contains(packageName))
            return;

        if (sHooking)
            return;

        mClassLoader = application.getClassLoader();

        reload();

        sHooking = hook(mClassLoader);
    }

    private static int getVUid() {
        return VClient.get().getVUid();
    }

    private void reload() {
        VLocation loc = VLocationManager.get().getCurAppLocation();
        if (loc == null)
            return;

        sLatitude = offset(loc.latitude);
        sLongitude = offset(loc.longitude);
    }

    private static double offset(double loc) {
        Random random = new Random();
        int r = random.nextInt(6) ;
        List<Double> li = new ArrayList<>();
        li.add(-0.00001);
        li.add(-0.00002);
        li.add(-0.00003);
        li.add(0.00001);
        li.add(0.00002);
        li.add(0.00003);
        double off = li.get(r);
        return off + loc;
    }

    private boolean hook(final ClassLoader classLoader) {
        try {
            final Class<?> aMapLocationClientClazz = findClass("com.amap.api.location.AMapLocationClient", classLoader);
            if (aMapLocationClientClazz == null) {
                XposedBridge.log("com.amap.api.location.AMapLocationClient is null .");
                return false;
            }
            XposedBridge.hookAllMethods(aMapLocationClientClazz, "setLocationListener", new XC_MethodHook() {
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    if (param.args.length == 1) {
                        Class<?> listenerClazz = param.args[0].getClass();
                        if (!LISTENER_CLASS.contains(listenerClazz.getName())) {
                            LISTENER_CLASS.add(listenerClazz.getName());
                            XposedBridge.hookAllMethods(listenerClazz, "onLocationChanged", new XC_MethodHook() {
                                @Override
                                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                    param.args[0] = fakeAMapLocationObject(param.args[0]);
                                    super.beforeHookedMethod(param);
                                }
                            });
                        }
                    }
                }
            });
        } catch (Error | Exception e) {
            XposedBridge.log(e);
            return false;
        }
        return true;
    }

    private Object fakeAMapLocationObject(Object object) {
        XposedHelpers.callMethod(object, "setLatitude", sLatitude);
        XposedHelpers.callMethod(object, "setLongitude", sLongitude);
        return object;
    }
}
